import json
import logging
import os
from os import path
import numpy as np

from command import CMD, CMD_SAVE_THRESHOLD
from worker import HANDLERS, WORKER
from defines import *

logger = logging.getLogger()

class config(dict, WORKER):

    handlers = HANDLERS()

    _DEFAULT_CFG_FILE = path.abspath('./cfg/cfg.json')
    __DEFAUT_CFG = {
        
        'host_ip':  '192.168.0.19',
        'udp_port':   4567,
        'tcp_port':   8902, 
        'netmask': '255.255.255.0',
        'gateway': '192.168.0.1',
        'pc_ip' : '255.255.255.255',
        'pc_port' : 8001,

        'os_uart' : '/dev/ttyPS1',
        'os_uart_baudrate' : 115200,

        'ch_sel': CHANEL_SEL.CH32,
        'bulk_size':50,
        # 'ind_interval': 0x3CA3D70A,     # 0.02 ns
        'start_pos': 1,       # 196250 GHz
        'scan_step': 5,
        'stop_pos' : 5101,    # 191150 GHz    
        'spec_length': (5101 - 1)//5,    # (stop_pos - start_pos) / scan_step
        'scan_speed' : 2,       # 1:1us/step; 2:2us/step; 3:10us/step; 4:980us/step;     
        'bypass_log': True,
        'bypass_fir': False,
        'use_fake_trig': False,

        'log_file':     './log/fbgi.log',
        'log_level':    logging.INFO,
        'log_fmt':      '%(asctime)s - %(levelname)-8s - [%(filename)s:%(lineno)d] %(message)s',

        'bitfile' : "/home/xilinx/FBGI_ZU3/bitstream/FBGI_ZU3.bit",
        'threshold_file' : '/home/xilinx/FBGI_ZU3/FBGI_32CH/cfg/thresholds.txt',
        'temp_calibrate_file' : '/home/xilinx/FBGI_ZU3/FBGI_32CH/cfg/temp_calibrate.txt',

        'software_version' : SW_VERSION,
        'serial'           : 0xFFFEFDFC,
        'amp'              : [0]*MAX_CH

    }


    def __init__(self, cfg_file=_DEFAULT_CFG_FILE) -> None:
        WORKER.__init__(self)
        if not path.exists(cfg_file):
            try:
                file_dir = path.split(cfg_file)[0]
                os.makedirs(file_dir, exist_ok=True)
                with open(cfg_file, 'w') as f:
                    pass
            except BaseException as e:
                logger.error("Create config json file failed.")
                logger.exception(e)
                cfg_file = self._DEFAULT_CFG_FILE
                 
        self.cfg_file = cfg_file

        with open(self.cfg_file, 'r') as f:
            try:
                cfg = json.load(f)
            except json.JSONDecodeError:
                logger.error("Cfg file parse error. Use default config.")
                cfg = self.__DEFAUT_CFG

        for k, v in self.__DEFAUT_CFG.items():
            if k in cfg:
                self[k] = cfg[k]
            else:
                self[k] = v

        try:
            self.thresholds = np.loadtxt(self.threshold_file, dtype='u2')
        except:
            logger.error("Thresholds file parse error. Use default thresholds 8000.")
            self.thresholds = np.ones((MAX_CH, MAX_SPEC_LENGTH), dtype='u2')*8000

        try:
            self.temp_calibrate = np.loadtxt(self.temp_calibrate_file, dtype='u2')
        except:
            logger.error("Temperature Calibration file parse error. Use default value 0.")
            self.temp_calibrate = np.zeros((TEMP_CAL_LEN), dtype='u2')
        

    def __setattr__(self, name: str, value) -> None:
        if type(value) is tuple:
            value = list(value)
        self[name] = value


    def __getattr__(self, name: str):
        return self.get(name)


    def __str__(self) -> str:
        return super(dict, self).__str__()

    # @handlers(CMD.Type.SAVE_THRESHOLD)
    def save_threshold(self):
        np.savetxt(self.threshold_file, self.thresholds, '%d')
        return True

    def save(self, file=None):
        used_file = self.cfg_file if file is None else file 

        need_write = {}
        for k in self.__DEFAUT_CFG.keys():
            need_write[k] = self[k]

        with open(used_file, 'w') as f:
            json.dump(need_write, f, sort_keys=True, indent=4, separators=(',', ': '))
        with open(used_file, 'r') as f:
            written = json.load(f)

        res = written == need_write
        if res == False:
            logger.error("Save config error.")
            logger.error("Need to be written to file : \n%s" % need_write)
            logger.error("!"*50)
            logger.error("Actually written to file : \n%s" % written)
        
        # np.savetxt(self.threshold_file, self.thresholds, '%d')

        return res

    # @handlers(CMD.Type.SAVE_CONFIG)
    # def save_config(self, cmd:CMD_SAVE_CONFIG):
    #     return self.save()
